package myJs.components

import cats.effect.SyncIO
import japgolly.scalajs.react.ReactMonocle._
import japgolly.scalajs.react._
import japgolly.scalajs.react.component.Scala.BackendScope
import japgolly.scalajs.react.extra.StateSnapshot
import japgolly.scalajs.react.vdom.all._
import monocle.Lens
import monocle.macros._
import myJs.Implicits._
import myJs.components.inline.{InputInlineComponent, SelectInlineComponent}
import myJs.myPkg.jquery._
import myJs.tool.Tool
import myJs.tool.Tool._

import scala.collection.immutable.SeqMap

/**
 * Created by yz on 3/11/2020
 */
object LimmaComponent {

  @Lenses
  case class State(groups: List[String], optionMap: SeqMap[String, String], covMap: Map[String, String],
                   covs: List[String], kinds: List[String], fillMethod: String, knn: String)

  object State {

    def init = {
      State(groups = List.empty, optionMap = SeqMap[String, String](), covMap = Map[String, String](),
        covs = List.empty, kinds = List.empty, fillMethod = "delete", knn = "5")
    }
  }

  class Backend(bs: BackendScope[Unit, State]) {

    val fieldNames = List("covs[]")

    def didMount(s: State) = {
      SyncIO {
        Tool.popover
        val bv = $("#form").bv
        fieldNames.foreach { fieldName =>
          val node = ReactDOM.findDOMNode(bs.raw).get.node
          val parentJq = $(node)
          val curJq = parentJq.findInputByName(fieldName)
          println(curJq.outerHTML)
          bv.addField(curJq)
        }
      }
    }

    def didUpdate(preS: State, curS: State) = {
      SyncIO {
        Tool.popover
        val bv = $("#form").bv
        List("covs[]").foreach { fieldName =>
          val node = ReactDOM.findDOMNode(bs.raw).get.node
          val parentJq = $(node)
          val curJq = parentJq.findInputByName(fieldName)
          println(curJq.outerHTML)
          bv.removeField(curJq).addField(curJq)
        }
      }

    }

    def unmount = {
      SyncIO {
        val bv = $("#form").bv
        val node = ReactDOM.findDOMNode(bs.raw).get.node
        val parentJq = $(node)
        fieldNames.foreach { fieldName =>
          val curJq = parentJq.findInputByName(fieldName)
          bv.updateStatus(curJq, "VALID").removeField(curJq)
        }
      }
    }


    def render(s: State) = {

      implicit class MyLens[T](lens: Lens[State, T]) {

        def zoomL(implicit r: Reusability[T]) = {
          StateSnapshot.withReuse.zoomL(lens).prepareVia(bs).apply(s)
        }

      }

      def deleteCov(i: Int) = {
        bs.modState { state =>
          state.copy(covs = state.covs.removed(i), kinds = state.kinds.removed(i))
        }
      }

      def addCov = {
        bs.modState { s =>
          val (cov, kind) = s.covMap.toList(s.covs.size)
          s.copy(covs = s.covs :+ (cov), kinds = s.kinds :+ (kind))
        }
      }

      def covChange(i: Int)(e: ReactEventFromInput) = {
        val myValue = e.target.value
        bs.modState { s =>
          val kindMap = getKindMap(s.covMap(myValue))
          val newKind = if (kindMap.contains(s.kinds(i))) {
            s.kinds(i)
          } else kindMap.head._1
          s.copy(covs = s.covs.updated(i, myValue), kinds = s.kinds.updated(i, newKind))
        }
      }

      def kindChange(i: Int)(e: ReactEventFromInput) = {
        val myValue = e.target.value
        bs.modState { s =>
          s.copy(kinds = s.kinds.updated(i, myValue))
        }
      }


      val canDelete = s.covs.size > 1
      val canAdd = s.covs.size < s.covMap.size
      val fillMethodMap = SeqMap("delete" -> messages("delete"), "modeFill" -> messages("modeFill"),
        "fillWithMedian" -> messages("fillWithMedian"))

      div(
        Select2MultipleInlineComponent.Props(State.groups.zoomL, label = messages("groups"),
          name = "groups[]", optionMap = s.optionMap).render,
        s.covs.zip(s.kinds).zipWithIndex.toVdomArray { case ((cov,kind), i) =>
          div(`class` := "form-group eachDiffFile",
            label(`class` := "control-label col-sm-2", s"${messages("covariate")}:"),
            div(`class` := "col-sm-2",
              select(`class` := "form-control", name := "covs[]", onChange ==> covChange(i),value:=s"${cov}",
                s.covMap.toVdomArray { case (v, text) =>
                  option(value := s"${v}", s"${v}")
                }
              ),
            ),
            label(`class` := "control-label col-sm-2", s"${messages("variableType")}:"),
            div(`class` := "col-sm-2",
              select(`class` := "form-control", name := "kinds[]", onChange ==> kindChange(i),value:=s"${kind}",
                getKindMap(s.covMap(cov)).toVdomArray { case (v, text) =>
                  option(value := s"${v}", s"${v}")
                }
              ),
            ),
            div(`class` := "col-sm-3",
              button(`type` := "button", `class` := "btn btn-default deleteButton",
                span(`class` := "fa fa-trash"), " ", messages("delete"), onClick --> deleteCov(i),
                disabled := (!canDelete))
            )
          )
        },
        div(`class` := "form-group",
          div(`class` := "actions col-sm-offset-2 col-sm-6",
            button(`type` := "button", `class` := "btn btn-default myAddColor", title := s"${messages("add")}",
              i(`class` := "fa fa-plus"), s" ${messages("add")}", onClick --> addCov, disabled := (!canAdd)
            )
          )
        ),
        SelectInlineComponent.Props(State.fillMethod.zoomL, label = messages("missingValueImputation"), name = "fillMethod",
          optionMap = fillMethodMap, labelWidth = 2, inputWidth = 3).render,
        InputInlineComponent.Props(State.knn.zoomL, show = (s.fillMethod == "knn"), label = messages("knnKValue"),
          name = "knn", labelWidth = 2, inputWidth = 3).
          render,

      )
    }

  }

  val Component = ScalaComponent.builder[Unit].initialState(State.init).renderBackend[Backend].
    componentDidMount(x => x.backend.didMount(x.state)).componentWillUnmount(_.backend.unmount).
    componentDidUpdate(x => x.backend.didUpdate(x.prevState, x.currentState)).
    build

}



